package com.mac.bluetoothbt.feature;


import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.support.annotation.ColorInt;
import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static com.mac.bluetoothbt.feature.FastBleService.backData;

class FrameUtil {
    /**
     * 应用时service uuid
     */
    static final String SERVICE_UUID = "0000fff0-0000-1000-8000-00805f9b34fb";

    /**
     * 应用时characteristic uuid
     */
    static final String CHARACTERISTIC_UUID = "0000fff6-0000-1000-8000-00805f9b34fb";

    //开发时service uuid
//    static final String SERVICE_UUID = "0000ffe0-0000-1000-8000-00805f9b34fb";
    //开发时characteristic uuid
//    static final String CHARACTERISTIC_UUID = "0000ffe1-0000-1000-8000-00805f9b34fb";

    static final float[] HIGH_LIMITS = new float[]{0, 0, 0, -100, 0, 0, 0, 0};
    static final float[] LOW_LIMITES = new float[]{1, 1.6f, 2.5f, 300, 200, 400, 600, 800};
    static final String[] BOUDRATES = {"2400", "4800", "9600", "19200", "38400"};
    static final String[] VOLUMES = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"};
    static final byte[] READ1ST = {(byte) 0xFF, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x32, (byte) 0xD1, (byte) 0xC1};
    /**
     * 静音和取消静音相同
     */
    static final byte[] SEND_SOUND_OFF = {(byte) 0xFF, (byte) 0x06, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x3D, (byte) 0xD4};
    static final byte[] sendafterallwrite = {(byte) 0xFF, (byte) 0x06, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x6C, (byte) 0x14};
    /**
     * 气体显示颜色
     */
    static private final @ColorInt
    int[]
            GASCOLORS = {Color.WHITE, Color.WHITE, Color.WHITE, 0xFF00FFE0, 0xFF00FFE0,
            Color.WHITE, Color.WHITE, 0xFF007BEF, 0xFF00307F,
            Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
            0xFF000077, 0xFF777777, 0xFF00BC40, 0xFF00FC07, 0xFF00FC07,
            Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE,
            Color.WHITE, Color.WHITE, Color.WHITE};


    static private final int[] BORDERS = {
            R.drawable.gas_border_blackwhite, R.drawable.gas_border_blackwhite, R.drawable.gas_border_blackwhite,
            R.drawable.gas_border_yellow, R.drawable.gas_border_yellow, R.drawable.gas_border_white,
            R.drawable.gas_border_black, R.drawable.gas_border_gray, R.drawable.gas_border_blue,
            R.drawable.gas_border_white, R.drawable.gas_border_white, R.drawable.gas_border_white,
            R.drawable.gas_border_blackwhite, R.drawable.gas_border_bluewhite, R.drawable.gas_border_graywhite,
            R.drawable.gas_border_redwhite, R.drawable.gas_border_red, R.drawable.gas_border_red,
            R.drawable.gas_border_white, R.drawable.gas_border_white, R.drawable.gas_border_white,
            R.drawable.gas_border_white, R.drawable.gas_border_white, R.drawable.gas_border_white,
            R.drawable.gas_border_white, R.drawable.gas_border_white, R.drawable.gas_border_white,
    };

    /**
     * 气体显示缩写
     */
    static private final String[] ABBREV = {
            "Med Air", "Air 800", "Dent Air", "Dent Vac", "Vac"
            , "O<sub>2</sub>", "N<sub>2</sub>", "CO<sub>2</sub>", "N<sub>2</sub>O", "Pin"
            , "Pout", "Syn Gas", "Syn Air", "O<sub>2</sub>/N<sub>2</sub>O", "O<sub>2</sub>/CO<sub>2</sub>"
            , "He/O<sub>2</sub>", "AGSS", "AGSS", "Access 1", "Access 2"
            , "Access 3", "Unused", "OXYGEN FLOW", "Argon", "Access 4"
            , "Access 5", "Access 6"
    };
    private static final String[] STATE_STRING = {"正常", "欠压", "超压", "未使用", "无信号输入"};
    private static final String[] UNITS = new String[]{"MPa", "MPa", "MPa", "kPa", "L/min", "L/min", "L/min", "L/min"};
    private static final String[] rangeString = new String[]{"0/1MPa", "0/1.6MPa", "0/2.5MPa", "-100/300kPa", "0-200L/min", "0-400L/min", "0-600L/min", "0-800L/min"};
    /**
     * \地址码\功能码\起始地址高\起始地址低\寄存器个数高\寄存器个数低\校验码高\校验码低\
     * 从 '起始地址'读'寄存器个数'个寄存器
     */
    private static final byte[] READALL = {(byte) 0xFF, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x46, (byte) 0xD1, (byte) 0xE6};
    private static final byte[] READ2ND = {(byte) 0xFF, (byte) 0x03, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x32, (byte) 0x70, (byte) 0x0E};
    private static final byte[] READPASSWORD_4 = {/*TODO*/};
    private static final byte[] READPASSWORD_6 = {(byte) 0xFF, (byte) 0x41, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x0D, (byte) 0xA8, (byte) 0x01};
    private static final byte[] READREMAINTIME6 = {(byte) 0xFF, (byte) 0x41, (byte) 0x01, (byte) 0x2C, (byte) 0x00, (byte) 0x0D, (byte) 0x29, (byte) 0xEB};
    private static final byte[] READPASSWORD8 = {(byte) 0xFF, (byte) 0x41, (byte) 0x00, (byte) 0xC8, (byte) 0x00, (byte) 0x0D, (byte) 0x68, (byte) 0x20};
    private static final byte[] READREMAINTIME8 = {(byte) 0xFF, (byte) 0x41, (byte) 0x01, (byte) 0x90, (byte) 0x00, (byte) 0x0D, (byte) 0xE8, (byte) 0x0F};
    private static final byte[] SENDTEST = {(byte) 0xFF, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xCD, (byte) 0xD4};

    /**
     * 组帧读寄存器
     *
     * @param address 地址
     * @param reghigh 高地址
     * @param reglow  低地址
     * @param regnum  要读寄存器数
     * @return 生成的数据帧
     */
    static byte[] createReadFrame(byte address, byte reghigh, byte reglow, int regnum) {
        byte[] tosend = new byte[8];
        tosend[0] = address;
        tosend[1] = 0x03;
        tosend[2] = reghigh;
        tosend[3] = reglow;
        tosend[4] = (byte) 0x00;
        tosend[5] = (byte) (regnum & 0xff);
        int crc = crc16Check(tosend, 6);
        tosend[6] = (byte) ((crc) & 0xff);
        tosend[7] = (byte) ((crc >> 8) & 0xff);
        return tosend;
    }

    /**
     * 读4个byte用于int/float的转化
     *
     * @param raw   源数组
     * @param index 从index开始
     * @return 4个byte的数组
     */
    static byte[] getdatafromhex(byte[] raw, int index) {
        byte[] midBytes = new byte[4];
        System.arraycopy(raw, index, midBytes, 0, 4);
        byte swap = midBytes[0];
        midBytes[0] = midBytes[3];
        midBytes[3] = swap;
        swap = midBytes[1];
        midBytes[1] = midBytes[2];
        midBytes[2] = swap;
        return midBytes;
    }

    /**
     * byte[]转为float
     *
     * @param bytes 输入值
     * @return float型结果
     * @throws IndexOutOfBoundsException index错误
     */
    static float bytes2float(byte[] bytes) throws IndexOutOfBoundsException {
        int midInt = 0x00000000;
        int mask = 0x000000ff;
        //由低到高
        midInt |= (bytes[0] & mask);
        midInt |= (bytes[1] & mask) << 8;
        midInt |= (bytes[2] & mask) << 16;
        midInt |= (bytes[3] & mask) << 24;

        return Float.intBitsToFloat(midInt);
    }

    /**
     * 2byte转为int
     *
     * @param bytes 输入值
     * @param index 索引
     * @return int型结果
     * @throws IndexOutOfBoundsException index错误
     */
    static int bytes2int16(byte[] bytes, int index) throws IndexOutOfBoundsException {
        int tmpint = 0;
        int mask = 0x000000ff;
        tmpint |= (bytes[index] & mask) << 8;
        tmpint |= (bytes[index + 1] & mask);
        return tmpint;
    }

    /**
     * 16进制byte[]转HexString
     *
     * @param bytes 输入值
     * @return 结果
     */
    static String bytesToHexString(byte[] bytes) {
        String result = "";
        for (int i : bytes
        ) {
            String hexString = Integer.toHexString(bytes[i] & 0xFF);
            if (hexString.length() == 1) {
                hexString = '0' + hexString;
            }
            result = result.concat(hexString.toUpperCase());
        }
        return result;
    }

    /**
     * CRC16/modbus校验
     *
     * @param Pushdata 待校验数据
     * @param length   CRC校验长度
     * @return CRC16结果，保存在int数据里
     */
    static int crc16Check(byte[] Pushdata, int length) {
        int Reg_CRC = 0xffff;
        int temp;
        int i, j;

        for (i = 0; i < length; i++) {
            temp = Pushdata[i];
            if (temp < 0) {
                temp += 256;
            }
            temp &= 0xff;
            Reg_CRC ^= temp;

            for (j = 0; j < 8; j++) {
                if ((Reg_CRC & 0x0001) == 0x0001) {
                    Reg_CRC = (Reg_CRC >> 1) ^ 0xA001;
                } else {
                    Reg_CRC >>= 1;
                }
            }
        }
        return (Reg_CRC & 0xffff);
    }

    /**
     * 获取气体种类索引
     *
     * @param index 气体种类索引
     * @return 气体名称
     */
    static String getGas(int index) {
        switch (index) {
            case 0:
                return "医疗空气";
            case 1:
                return "器械空气";
            case 2:
                return "牙科空气";
            case 3:
                return "牙科真空";
            case 4:
                return "医用真空";
            case 5:
                return "医用氧气";
            case 6:
                return "氮气";
            case 7:
                return "二氧化碳";
            case 8:
                return "氧化亚氮";
            case 9:
                return "输入压力";
            case 10:
                return "输出压力";
            case 11:
                return "混合气体";
            case 12:
                return "合成气体";
            case 13:
                return "氧/氧化亚氮";
            case 14:
                return "氧/二氧化碳";
            case 15:
                return "氦气/氧气";
            case 16:
                return "麻醉废气";
            case 17:
                return "呼吸废气";
            case 18:
                return "通道1";
            case 19:
                return "通道2";
            case 20:
                return "通道3";
            case 21:
                return "未使用";
            case 22:
                return "氧气流量";
            case 23:
                return "氩气";
            case 24:
                return "通道4";
            case 25:
                return "通道5";
            case 26:
                return "通道6";
            default:
                return null;
        }
    }

    static String getAbb(int index) {
        if (index >= ABBREV.length) {
            index = 0;
        }
        return ABBREV[index];
    }

    /**
     * 获得气体颜色
     *
     * @param gasIndex 气体索引
     * @return LightingColorFilter
     */
    static ColorFilter getGasColor(int gasIndex) {
        if (gasIndex > GASCOLORS.length - 1) {
            return new LightingColorFilter(0xff000000, Color.WHITE);
        }

        int add = GASCOLORS[gasIndex];
        return new LightingColorFilter(0xff000000, add);
    }

    static int getGasColorDrawableId(int gasIndex) {
        return BORDERS[gasIndex];
    }

    /**
     * 用气体名获得索引
     *
     * @param gasName 气体名
     * @return 气体索引
     */
    static int getGasIndex(String gasName) {
        int index = 0;
        if (gasName == null) {
            return -1;
        }
        while (getGas(index) != null) {
            if (gasName.equals(getGas(index))) {
                return index;
            }
            index++;
        }
        return -1;
    }

    /**
     * 读取所有气体
     *
     * @return 所有气体
     */
    static List<String> getAllGas() {
        List<String> allgas = new ArrayList<>();
        int index = 0;
        String gas = getGas(index);
        while (gas != null) {
            allgas.add(gas);
            gas = getGas(++index);
        }
        return allgas;
    }

    /**
     * 获取状态索引
     *
     * @param index 状态索引
     * @return 得到索引对应状态
     */
    static String getState(int index) {
        if (index >= STATE_STRING.length) {
            index = 4;
        }
        return STATE_STRING[index];
    }

    /**
     * 用String取得对应index
     *
     * @param stateString 应为stateString中
     * @return index
     */
    static int getStateIndex(String stateString) {
        for (int i = 0; i < STATE_STRING.length; i++) {
            if (stateString.equals(STATE_STRING[i])) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 获得量程
     *
     * @param index 序号
     * @return 量程
     */
    static String getRange(int index) {
        return String.format(Locale.PRC, "%f/%f%s", getLowLimit(index),
                getHighLimit(index), getUnit(index));
    }

    /**
     * 获得量程列表
     *
     * @return 所有量程
     */
    static List<String> getAllRanges() {
        return new ArrayList<>(Arrays.asList(rangeString));
    }

    static int getRangeIndex(String range) {
        for (int i = 0; i < rangeString.length; i++) {
            if (rangeString[i].equals(range)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 获得下限
     *
     * @param index 量程索引
     * @return 下限
     */
    private static float getLowLimit(int index) {
        return LOW_LIMITES[index];
    }

    /**
     * 获得上限
     *
     * @param index 量程索引
     * @return 上限
     */
    private static float getHighLimit(int index) {
        return HIGH_LIMITS[index];
    }

    /**
     * 获得单位
     *
     * @param index 量程索引
     * @return 单位
     */
    static String getUnit(int index) {
        return UNITS[index];
    }

    /**
     * <p>读一轮寄存器</p>
     *
     * @param context 上下文
     */
    static void oneTurnRequest(Context context, Timer timer) {
        try {
            sendBle(context, READ1ST);

            final Context context1 = context;
            TimerTask secondframe = new TimerTask() {
                @Override
                public void run() {
                    sendBle(context1, READ2ND);
                }
            };

            timer.schedule(secondframe, 3000);
        } catch (Exception e) {
            Log.e("Exception Error", e.toString());
        }
    }

    /**
     * <p>读4位密码</p>
     *
     * @param context 上下文
     */
    static void readPassword4(Context context) {
        sendBle(context, READPASSWORD_4);
    }

    /**
     * <p>读6位密码</p>
     *
     * @param context 上下文
     */
    static void readPassword6(Context context) {
        sendBle(context, READPASSWORD_6);
    }

    /**
     * 读6位授权时间
     *
     * @param context 上下文
     */
    static void readremaintime6(Context context) {
        App.timeReadTime++;
        sendBle(context, READREMAINTIME6);
    }

    /**
     * <p>读8位密码</p>
     *
     * @param context 上下文
     */
    static void readPassword8(Context context) {
        sendBle(context, READPASSWORD8);
    }

    /**
     * 读8位授权时间
     *
     * @param context 上下文
     */
    static void readremaintime8(Context context) {
        sendBle(context, READREMAINTIME8);
    }

    static void setPassword6(Context context, String password) {
        final int len = 22;
        int idx = 0;
        byte[] setFrame = new byte[len];
        setFrame[idx++] = (byte) 0xFF;
        setFrame[idx++] = (byte) 0x42;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x64;

        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x06;
        setFrame[idx++] = (byte) 0x0d;

        setFrame[idx++] = (byte) password.charAt(0);
        setFrame[idx++] = (byte) password.charAt(1);
        setFrame[idx++] = (byte) password.charAt(2);
        setFrame[idx++] = (byte) password.charAt(3);
        setFrame[idx++] = (byte) password.charAt(4);
        setFrame[idx++] = (byte) password.charAt(5);
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x14;
        int crc = crc16Check(setFrame, len - 2);
        setFrame[idx++] = (byte) ((crc) & 0xff);
        setFrame[idx++] = (byte) ((crc >> 8) & 0xff);
        sendBle(context, setFrame);
    }

    static void setPassword8(Context context, String password) {
        final int len = 22;
        int idx = 0;
        byte[] setFrame = new byte[len];
        setFrame[idx++] = (byte) 0xFF;
        setFrame[idx++] = (byte) 0x42;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0xC8;//0x00, 0x06, 0x0d

        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x06;
        setFrame[idx++] = (byte) 0x0d;

        setFrame[idx++] = (byte) password.charAt(0);
        setFrame[idx++] = (byte) password.charAt(1);
        setFrame[idx++] = (byte) password.charAt(2);
        setFrame[idx++] = (byte) password.charAt(3);
        setFrame[idx++] = (byte) password.charAt(4);
        setFrame[idx++] = (byte) password.charAt(5);
        setFrame[idx++] = (byte) password.charAt(6);
        setFrame[idx++] = (byte) password.charAt(7);
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x14;
        int crc = crc16Check(setFrame, len - 2);
        setFrame[idx++] = (byte) ((crc) & 0xff);
        setFrame[idx++] = (byte) ((crc >> 8) & 0xff);
        sendBle(context, setFrame);
    }

    static void setRemainTime6(Context context, int time) {
        int len = 10;
        int idx = 0;
        byte[] setFrame = new byte[len];
        setFrame[idx++] = (byte) 0xFF;
        setFrame[idx++] = (byte) 0x42;
        setFrame[idx++] = (byte) 0x01;
        setFrame[idx++] = (byte) 0x2C;

        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x02;

        setFrame[idx++] = (byte) ((time >> 8) & 0xff);
        setFrame[idx++] = (byte) (time & 0xff);
        int crc = crc16Check(setFrame, len - 2);
        setFrame[idx++] = (byte) ((crc) & 0xff);
        setFrame[idx++] = (byte) ((crc >> 8) & 0xff);
        sendBle(context, setFrame);
    }

    static void setRemainTime8(Context context, int time) {
        int len = 10;
        int idx = 0;
        byte[] setFrame = new byte[len];
        setFrame[idx++] = (byte) 0xFF;
        setFrame[idx++] = (byte) 0x42;
        setFrame[idx++] = (byte) 0x01;
        setFrame[idx++] = (byte) 0x90;

        setFrame[idx++] = (byte) 0x00;
        setFrame[idx++] = (byte) 0x02;

        setFrame[idx++] = (byte) ((time >> 8) & 0xff);
        setFrame[idx++] = (byte) (time & 0xff);
        int crc = crc16Check(setFrame, len - 2);
        setFrame[idx++] = (byte) ((crc) & 0xff);
        setFrame[idx++] = (byte) ((crc >> 8) & 0xff);
        sendBle(context, setFrame);
    }

    /**
     * 获得剩余时间
     *
     * @param data 数据
     * @return 剩余时间
     */
    static int getRemainTime(byte[] data) {
        int val = 0;
        val |= (data[3] & 0xff) << 8;
        val |= data[3 + 1] & 0xff;
        return val;
    }

    /**
     * <p>发送测试命令</p>
     */
    static void sendTest(Context context) {
        sendBle(context, SENDTEST);
    }

    static void setSendSoundOn(Context context) {
        sendBle(context, SEND_SOUND_OFF);
    }

    static void sendSilent(Context context) {
        sendBle(context, SEND_SOUND_OFF);
    }

    /**
     * 发送完后调用
     *
     * @param context 上下文
     */
    static public void sendAfterAllwrite(Context context) {
        sendBle(context, sendafterallwrite);
    }

    /**
     * 写一组数据
     *
     * @param context 上下文
     * @param bytes   要写的数据
     */
    static void writeAllRegister(final Context context, List<byte[]> bytes)
            throws WriteRegisterNoBackException {
        boolean hasBack;


        int count = 0;
        for (int i = 0; i < bytes.size(); i++) {
            if (count == 3) {
                throw new WriteRegisterNoBackException();
            }
            sendBle(context, bytes.get(i));
            if (Arrays.equals(bytes.get(i), sendafterallwrite)) {
                hasBack = waitForBack(sendafterallwrite);
                Log.d("debug", "FF060003接收" + hasBack);
            } else {
                hasBack = waitBack(bytes.get(i));
            }
            if (!hasBack) {
                Log.d("debug", "backFoundFailed" + count);
            }
            if (!hasBack) {

                count++;
                i--;
                continue;
            }
            count = 0;
            while (!FastBleService.sendMsgQueue.isEmpty()) {

            }
        }
        sendBle(context);
    }

    private static boolean waitForBack(final byte[] sa) {
        Boolean aBoolean = FrameUtil.timeoutProcess(
                new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        try {

                            while (true) {
                                if (Arrays.equals(backData, sa)) {
                                    return true;
                                }
                                Thread.sleep(10);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        return false;
                    }
                }
        );
        return aBoolean == null ? false : aBoolean;
    }

    private static boolean waitBack(final byte[] wdata) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Boolean> future = executorService.submit(new Callable<Boolean>() {
            int timegap = 10;

            @Override
            public Boolean call() throws Exception {
                while (true) {
                    byte[] bdata = backData;
                    if (bdata != null) {
                        if (wdata[2] == bdata[2] &&
                                wdata[3] == bdata[3] &&
                                wdata[4] == bdata[4] &&
                                wdata[5] == bdata[5]) {
                            Log.d("debug", "backFound in thread "
                                    + Thread.currentThread().getName());

                            return true;
                        }
                    }
                    Thread.sleep(timegap);
                }
            }
        });
        try {
            boolean ret = future.get(1000, TimeUnit.MILLISECONDS);
            Log.d("debug", "backFound" + ret + "future");
            return ret;
        } catch (TimeoutException e) {
            future.cancel(true);
            return false;
        } catch (InterruptedException e) {
            future.cancel(true);
        } catch (Exception e) {
            future.cancel(true);
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
        Log.d("debug", "backFoundNot");
        return true;
    }

    /**
     * 超时
     *
     * @param task Callable<T>
     * @return 任务返回
     */
    private static <T> T timeoutProcess(Callable<T> task) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<T> future = executor.submit(task);
        try {
            return future.get(30000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            if (future.isCancelled()) {
                future.cancel(true);
            }
        }
        return null;
    }

    /**
     * 写几个寄存器
     *
     * @param context  上下文
     * @param data     数据
     * @param address  从机地址
     * @param regstart 开始位置
     * @param regnum   几个
     */
    static private byte[] writeRegister(Context context, byte[] data, int address, int regstart, int regnum) {
        byte[] frame = new byte[regnum * 2 + 9];
        frame[0] = (byte) (address & 0xff);
        frame[1] = (byte) 0x10;

        frame[2] = (byte) ((regstart >> 8) & 0xff);
        frame[3] = (byte) ((regstart) & 0xff);

        frame[4] = (byte) ((regnum >> 8) & 0xff);
        frame[5] = (byte) ((regnum) & 0xff);

        regnum *= 2;
        frame[6] = (byte) (regnum & 0xff);

        System.arraycopy(data, regstart * 2 + 1, frame, 7, regnum);

        int crc = crc16Check(frame, frame.length - 2);
        frame[frame.length - 2] = (byte) (crc & 0xff);
        frame[frame.length - 1] = (byte) ((crc >> 8) & 0xff);
        sendBle(context, frame);
        return frame;
    }

    /**
     * 蓝牙发送数据
     *
     * @param context 上下文
     * @param data    数据
     */
    static private void sendBle(Context context, byte[] data) {
        WriteWithCallback write = new WriteWithCallback(data);
        context.sendBroadcast(new Intent(Actions.ACTION_WRITE).putExtra("writebytes", write));
    }

    static private void sendBle(Context context) {
        WriteWithCallback write = new WriteWithCallback(null, WriteWithCallback.WRITE_END);
        context.sendBroadcast(new Intent(Actions.ACTION_WRITE).putExtra("writebytes", write));
    }

    /**
     * 生成写寄存器帧
     *
     * @param data     数据
     * @param regstart 从regstart处开始拷贝
     * @param regnum   拷贝的寄存器个数
     * @return 写寄存器帧
     */
    static byte[] getWriteRegisterFrame(byte[] data, int regstart, int regnum) {
        byte[] frame = new byte[regnum * 2 + 9];
        frame[0] = (byte) (0xff);
        frame[1] = (byte) 0x10;

        frame[2] = (byte) ((regstart >> 8) & 0xff);
        frame[3] = (byte) ((regstart) & 0xff);

        frame[4] = (byte) ((regnum >> 8) & 0xff);
        frame[5] = (byte) ((regnum) & 0xff);

        regnum *= 2;
        frame[6] = (byte) (regnum & 0xff);

        System.arraycopy(data, regstart * 2 + 1, frame, 7, regnum);

        int crc = crc16Check(frame, frame.length - 2);
        frame[frame.length - 2] = (byte) (crc & 0xff);
        frame[frame.length - 1] = (byte) ((crc >> 8) & 0xff);
        return frame;
    }

    /**
     * 生成反向写寄存器帧
     *
     * @param data     数据
     * @param regstart 从regstart处开始拷贝
     * @return 写寄存器帧
     */
    static byte[] getWriteReverseRegisterFrame(byte[] data, int regstart, int regr) {
        byte[] frame = new byte[11];
        frame[0] = (byte) (0xff);
        frame[1] = (byte) 0x10;

        frame[2] = (byte) ((regstart >> 8) & 0xff);
        frame[3] = (byte) ((regstart) & 0xff);

        frame[4] = 0x00;
        frame[5] = 0x01;

        frame[6] = 0x02;

        int st = regr * 2 + 1;
        frame[7] = data[st];
        frame[8] = data[st + 1];

        int crc = crc16Check(frame, frame.length - 2);
        frame[frame.length - 2] = (byte) (crc & 0xff);
        frame[frame.length - 1] = (byte) ((crc >> 8) & 0xff);
        return frame;
    }

    enum SensorStatus {
        /**
         * 正常
         */
        NORMAL,
        /**
         * 欠压
         */
        BELOWMIN,
        /**
         * 超压
         */
        OVERMAX,
        /**
         * 未使用
         */
        NOTUSED,
        /**
         * 无信号输入
         */
        NOSIGNAL,
    }

    static class WriteRegisterNoBackException extends Exception {
    }

}
